---
title: Компоненты
description: Введение в синтаксис компонентов Astro.
i18nReady: true
---
import ReadMore from '~/components/ReadMore.astro';

**Компоненты Astro** являются основными строительными блоками любого проекта Astro. Они представляют собой HTML-шаблоны, которые не требуют выполнения на стороне клиента. Определить компонент Astro можно по расширению файла: `.astro`.

:::note
Если вы знаете HTML, у вас уже достаточно знаний, чтобы написать свой первый компонент Astro.

<ReadMore>Узнайте больше в [справочнике по синтаксису Astro](/ru/reference/astro-syntax/).</ReadMore>
:::

Компоненты Astro чрезвычайно гибки. Часто компонент Astro будет содержать некоторый **повторно используемый UI на странице**, например заголовок или карточку профиля. В других случаях компонент Astro может содержать небольшой фрагмент HTML, например набор общих `<meta>` тегов, которые упрощают работу с SEO. Компоненты Astro могут даже содержать макет страницы целиком.

Самое главное, что нужно знать о компонентах Astro, — это то, что **они не отрисовываются на клиенте**. Они преобразуются в HTML либо во время сборки, либо по требованию. Вы можете включить JavaScript-код внутри блока метаданных вашего компонента, и он весь будет удален с конечной страницы, отправленной в браузеры ваших пользователей. В результате получается более быстрый сайт с нулевым использованием JavaScript по умолчанию.

Когда вашему компоненту Astro действительно требуется интерактивность на стороне клиента, вы можете добавить [стандартные теги HTML `<script>`](/ru/guides/client-side-scripts/) или [компоненты UI фреймворков](/ru/guides/framework-components/#hydrating-interactive-components) как «клиентские островки».

Для компонентов, которым требуется отображать персонализированный или динамический контент, вы можете отложить их рендеринг на сервере, добавив [директиву `server`](/ru/reference/directives-reference/#server-directives). Эти «серверные островки» будут отображать свой контент, когда он станет доступен, не задерживая загрузку всей страницы.

## Структура компонента

Компонент Astro состоит из двух основных частей: **Скрипта компонента** и **Шаблона компонента**. Каждая часть выполняет свою работу, но вместе они обеспечивают структуру, которая одновременно проста в использовании и достаточно выразительна, чтобы справиться с тем, что вы захотите создать.

```astro title="src/components/EmptyComponent.astro"
---
// Скрипт компонента (JavaScript)
---
<!-- Шаблон компонента (HTML + выражения JS) -->
```

### Скрипт компонента

Astro использует блок кода (`---`) для идентификации скрипта в вашем компоненте Astro. Если вы когда-либо писали Markdown раньше, возможно, вы уже знакомы с похожей концепцией, называемой *метаданные*. Идея Astro о скрипте компонента была непосредственно вдохновлена этой концепцией.

Вы можете использовать скрипт компонента для написания любого кода JavaScript, необходимого для визуализации шаблона. Это может включать в себя:

- импорт других компонентов Astro
- импорт компонентов из других фреймворков, таких как React
- импорт данных, например файла JSON
- получение контента из API или базы данных
- создание переменных, на которые вы будете ссылаться в своем шаблоне

```astro title="src/components/MyComponent.astro"
---
import SomeAstroComponent from '../components/SomeAstroComponent.astro';
import SomeReactComponent from '../components/SomeReactComponent.jsx';
import someData from '../data/pokemon.json';

// Доступ к пропсам компонента, таким как `<X title="Привет, мир" />`
const {title} = Astro.props;

// Получение внешних данных, даже из приватного API или базы данных
const data = await fetch('SOME_SECRET_API_URL/users').then(r => r.json());
---
<!-- Здесь ваш шаблон! -->
```

Блок кода предназначен для того, чтобы гарантировать, что написанный в нём JavaScript остаётся «изолированным». Он не попадёт в ваше фронтенд-приложение и не окажется в руках пользователя. Здесь можно безопасно писать код, который является ресурсоёмким или чувствительным (например, подключение к вашей приватной базе данных), не беспокоясь о том, что он когда-либо попадёт в браузер пользователя.

:::note
Скрипт компонента Astro написан на TypeScript, что позволяет добавлять дополнительный синтаксис к JavaScript для поддержки инструментов редактора и проверки ошибок.

<ReadMore>Узнайте больше о [встроенной поддержке TypeScript в Astro](/ru/guides/typescript/).</ReadMore>
:::

### Шаблон компонента

Шаблон компонента следует за блоком кода и определяет вывод HTML вашего компонента.

Если вы напишете здесь простой HTML, ваш компонент будет отображать этот HTML на любой странице Astro, в которую он импортирован и используется.

Однако, [синтаксис Astro](/ru/reference/astro-syntax/) так же поддерживает **JavaScript выражения**, теги [`<style>`](/ru/guides/styling/#стилизация-в-astro) и [`<script>`](/ru/guides/client-side-scripts/#client-side-scripts) Astro, **импортированные компоненты**, и [**специальные директивы Astro**](/ru/reference/directives-reference/). Данные и значения, определённые в скрипте компонента, можно использовать в шаблоне компонента для создания динамически создаваемого HTML.

```astro title="src/components/MyFavoritePokemon.astro"
---
// Здесь ваш скрипт компонента!
import Banner from '../components/Banner.astro';
import Avatar from '../components/Avatar.astro';
import ReactPokemonComponent from '../components/ReactPokemonComponent.jsx';
const myFavoritePokemon = [/* ... */];
const { title } = Astro.props;
---
<!-- Поддерживаются HTML коментарии! -->
{/* Синтаксис комментариев JS также действителен! */}

<Banner />
<h1>Привет, мир!</h1>

<!-- Используем пропсы и другие переменные из скрипта компонента: -->
<p>{title}</p>

<!-- Осуществляем отложенный рендеринг компонента с резервным контентом для загрузки: -->
<Avatar server:defer>
  <svg slot="fallback" class="generic-avatar" transition:name="avatar">...</svg>
</Avatar>

<!-- Включаем другие компоненты пользовательского интерфейса с помощью директивы `client`: для гидратации: -->
<ReactPokemonComponent client:visible />

<!-- Комбинируем HTML с выражениями JavaScript, как в JSX: -->
<ul>
  {myFavoritePokemon.map((data) => <li>{data.name}</li>)}
</ul>

<!-- Используем директиву шаблона для создания имён классов из нескольких строк или даже объектов! -->
<p class:list={["add", "dynamic", {classNames: true}]} />
```

## Компонентный дизайн

Компоненты спроектированы так, чтобы их можно было **повторно использовать** и **компоновать**. Вы можете использовать компоненты внутри других компонентов для создания более продвинутого пользовательского интерфейса. Например, компонент `Button` можно использовать для создания компонента `ButtonGroup`:

```astro title="src/components/ButtonGroup.astro"
---
import Button from './Button.astro';
---
<div>
  <Button title="Кнопка 1" />
  <Button title="Кнопка 2" />
  <Button title="Кнопка 3" />
</div>
```

## Пропсы компонента

Компонент Astro может определять и принимать входные параметры — пропсы. Эти пропсы затем становятся доступными шаблону компонента для рендеринга HTML. Пропсы доступны в глобальном объекте `Astro.props` в вашем скрипте.

Вот пример компонента, который получает пропсы `greeting` и `name`. Обратите внимание, что получаемые входные параметры деструктурированы из глобального объекта `Astro.props`.

```astro "Astro.props"
---
// src/components/GreetingHeadline.astro
// Применение: <GreetingHeadline greeting="Привет" name="Партнёр" />
const { greeting, name } = Astro.props;
---
<h2>{greeting}, {name}!</h2>
```

Этот компонент при импорте и визуализации в других компонентах Astro, макетах или страницах может передавать эти параметры в качестве атрибутов:

```astro /(\w+)=\S+/
---
// src/components/GreetingCard.astro
import GreetingHeadline from './GreetingHeadline.astro';
const name = "Astro"
---
<h1>Поздравительная открытка</h1>
<GreetingHeadline greeting="Привет" name={name} />
<p>Надеюсь, у вас чудесный день!</p>
```

Вы также можете определить свои пропсы с помощью TypeScript с интерфейсом типа `Props`. Astro автоматически подхватит интерфейс `Props` в вашем блоке метаданных и выдаст предупреждения/ошибки типа. Этим входным параметрам также могут быть присвоены значения по умолчанию при деструктуризации из `Astro.props`.

```astro ins={3-6}
---
// src/components/GreetingHeadline.astro
interface Props {
  name: string;
  greeting?: string;
}

const { greeting = "Привет", name } = Astro.props;
---
<h2>{greeting}, {name}!</h2>
```

Пропсам компонента могут быть присвоены значения по умолчанию, которые можно использовать, если они не указаны.

```astro ins="= \"Привет\"" ins="= \"Астронавт\""
---
// src/components/GreetingHeadline.astro
const { greeting = "Привет", name = "Астронавт" } = Astro.props;
---
<h2>{greeting}, {name}!</h2>
```

## Слоты

`<slot />` это заполнитель для внешнего HTML-содержимого, позволяющий вставлять дочерние элементы из других файлов в шаблон компонента.

По умолчанию все дочерние элементы, переданные компоненту, будут отображаться в его `<slot />`.

:::note
В отличие от _пропсов_, которые являются атрибутами, передаваемыми компоненту Astro, доступными для использования во всем вашем компоненте с помощью `Astro.props`, _слоты_ отображают дочерние элементы HTML там, где они написаны.
:::

```astro "<slot />"
---
// src/components/Wrapper.astro
import Header from './Header.astro';
import Logo from './Logo.astro';
import Footer from './Footer.astro';

const { title } = Astro.props
---
<div id="content-wrapper">
  <Header />
  <Logo />
  <h1>{title}</h1>
  <slot />  <!-- дочерний элемент будет здесь -->
  <Footer />
</div>
```

```astro {6-7}
---
// src/pages/fred.astro
import Wrapper from '../components/Wrapper.astro';
---
<Wrapper title="Fred's Page">
  <h2>Всё о Фреде</h2>
  <p>Вот немного информации о Фреде.</p>
</Wrapper>
```

Этот шаблон является основой [компонента макета Astro](/ru/basics/layouts/): целая страница HTML-контента может быть «обёрнута» тегами `<SomeLayoutComponent></SomeLayoutComponent>` и передана компоненту для отрисовки внутри определённых в нем общих элементов страницы.

### Именованные слоты

Компонент Astro также может иметь именованные слоты. Это позволяет передавать в местоположение слота только элементы HTML с соответствующим именем слота.

Слоты именуются с помощью атрибута `name`:

```astro /<slot .*?/>/
---
// src/components/Wrapper.astro
import Header from './Header.astro';
import Logo from './Logo.astro';
import Footer from './Footer.astro';

const { title } = Astro.props
---
<div id="content-wrapper">
  <Header />
  <!--  дочерние элементы с атрибутом `slot="after-header"` будут находиться здесь -->
  <slot name="after-header"/>
  <Logo />
  <h1>{title}</h1>
  <!--  дочерние элементы без `slot`, или с `slot="default"` будут находиться здесь -->
  <slot />
  <Footer />
  <!--  дочерние элементы с атрибутом `slot="after-footer"` будут находиться здесь -->
  <slot name="after-footer"/>
</div>
```

Чтобы внедрить HTML-контент в определённый слот, используйте атрибут `slot` в любом дочернем элементе, чтобы указать имя слота. Все остальные дочерние элементы компонента будут вставлены в стандартный (безымянный) `<slot />`.

```astro /slot=".*?"/
---
// src/pages/fred.astro
import Wrapper from '../components/Wrapper.astro';
---
<Wrapper title="Страница Фреда">
  <img src="https://my.photo/fred.jpg" slot="after-header">
  <h2>Всё о Фреде</h2>
  <p>Вот немного информации о Фреде.</p>
  <p slot="after-footer">Авторское право 2022</p>
</Wrapper>
```

:::tip
Используйте атрибут `slot="my-slot"` в дочернем элементе, который вы хотите передать в соответствующий заполнитель `<slot name="my-slot" />` в вашем компоненте.
:::

Чтобы передать несколько HTML-элементов в заполнитель `<slot/>` компонента без обёртывающего `<div>`, используйте атрибут `slot=""` на компоненте [`<Fragment/>` Astro](/ru/reference/astro-syntax/#fragments):

```astro title="src/components/CustomTable.astro" "<slot name="header"/>" "<slot name="body"/>"
---
//  Создание пользовательской таблицы с именованными заполнителями для заголовка и тела контента
---
<table class="bg-white">
  <thead class="sticky top-0 bg-white"><slot name="header" /></thead>
  <tbody class="[&_tr:nth-child(odd)]:bg-gray-100"><slot name="body" /></tbody>
</table>
```

Вставьте несколько строк и столбцов HTML-контента с помощью атрибута `slot=""`, чтобы указать содержимое `"header"` и `"body"`. Отдельные элементы HTML также можно стилизовать:

```astro title="src/components/StockTable.astro" {5-7, 9-13} '<Fragment slot="header">' '<Fragment slot="body">'
---
import CustomTable from './CustomTable.astro';
---
<CustomTable>
  <Fragment slot="header"> <!-- передаём заголовок таблицы -->
    <tr><th>Название продукта</th><th>Единицы на складе</th></tr>
  </Fragment>

  <Fragment slot="body"> <!-- передаём тело таблицы -->
    <tr><td>Шлёпанцы</td><td>64</td></tr>
    <tr><td>Ботинки</td><td>32</td></tr>
    <tr><td>Кроссовки</td><td class="text-red-500">0</td></tr>
  </Fragment>
</CustomTable>
```

Обратите внимание, что именованные слоты должны быть непосредственными дочерними элементами компонента. Вы не можете передавать именованные слоты через вложенные элементы.

:::tip
Именованные слоты также можно передавать в [компоненты UI фреймворков](/ru/guides/framework-components/)!
:::

:::note
Невозможно динамически генерировать имя слота Astro, например, внутри функции [map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map). Если эта функция необходима в компонентах UI-фреймворка, лучше всего генерировать эти динамические слоты внутри самого фреймворка.
:::

### Резервный контент для слотов

Слоты также могут отображать **резервный контент**. Когда в слот не передаются соответствующие дочерние элементы, элемент `<slot />` отобразит свои собственные дочерние элементы-заполнители.

```astro {14}
---
// src/components/Wrapper.astro
import Header from './Header.astro';
import Logo from './Logo.astro';
import Footer from './Footer.astro';

const { title } = Astro.props
---
<div id="content-wrapper">
  <Header />
  <Logo />
  <h1>{title}</h1>
  <slot>
    <p>Это резервное содержимое, если в слот не передан дочерний элемент</p>
  </slot>
  <Footer />
</div>
```

Резервный контент будет отображаться только в том случае, если нет соответствующих элементов с атрибутом `slot="name"`, передаваемых в именованный слот.

Astro передаст пустой слот, если элемент слота существует, но не содержит контента для передачи. Резервный контент нельзя использовать в качестве значения по умолчанию, когда передаётся пустой слот. Резервный контент отображается только тогда, когда элемент слота не найден.

### Перенос слотов

Слоты можно передавать другим компонентам. Например, при создании вложенных макетов:

```astro title="src/layouts/BaseLayout.astro" {9,12}
---
---
<html lang="en">
	<head>
		<meta charset="utf-8" />
		<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
		<meta name="viewport" content="width=device-width" />
		<meta name="generator" content={Astro.generator} />
    <slot name="head"/>
	</head>
	<body>
		<slot />
	</body>
</html>
```

```astro {6,7}
// src/layouts/HomeLayout.astro
---
import BaseLayout from "./BaseLayout.astro";
---
<BaseLayout>
  <slot name="head" slot="head"/>
  <slot />
</BaseLayout>
```

:::note
Именованные слоты могут быть переданы другому компоненту, используя атрибуты `name` и `slot` в теге `<slot />`
:::

Теперь содержимое стандартного (безымянного) слота и слота `head`, переданных в `HomeLayout`, будет перенесено в родительский компонент `BaseLayout`.

```astro
// src/pages/index.astro
---
import HomeLayout from "../layouts/HomeLayout.astro";
---
<HomeLayout>
	<title slot="head">Astro</title>
	<h1>Astro</h1>
</HomeLayout>
```

## HTML-компоненты

Astro поддерживает импорт и использование `.html` файлов в качестве компонентов или размещение этих файлов в подкаталоге `src/pages/` в качестве страниц. Возможно, вам захочется использовать HTML-компоненты, если вы повторно используете код с существующего сайта, созданного без фреймворка, или если вы хотите убедиться, что ваш компонент не имеет динамических функций.

HTML-компоненты должны содержать только валидный HTML, поэтому они лишены ключевых возможностей компонентов Astro:

- Они не поддерживают метаданные, импорт на стороне сервера или динамические выражения.
- Любые теги `<script>` остаются неупакованными, и обрабатываются, как если бы у них был атрибут `is:inline`.
- Они могут только [ссылаться на ресурсы, которые находятся в папке `public/`](/ru/basics/project-structure/#public).

:::note
В HTML-компоненте элемент [`<slot />`](/ru/basics/astro-components/#слоты) будет работать так же, как и в компоненте Astro. Чтобы использовать [HTML Web Component Slot](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot ), добавьте атрибут `is:inline` к вашему элементу `<slot>`.
:::

## Следующие шаги

<ReadMore>Узнайте больше об использовании [UI компонентов фреймворков](/ru/guides/framework-components/) в вашем проекте Astro.</ReadMore>
